﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CodeCounterApp
{
    public partial class MainForm : Form
    {
        private Dictionary<string, List<string>> _type2Files = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
        private static readonly List<string> _usuallyTypes = new List<string> { ".h", ".cpp", ".cs" };// 默认勾选的类型
        private static string _recentFolderPath = Path.Combine(Path.GetTempPath(), "CodeCounterAppRecentFolder.txt");
        private System.Windows.Forms.Timer _formTimer;// 清理历史记录时需从TextChanged事件响应函数中清空界面，此时界面不执行，改为使用计时器执行

        List<string> _selectedItems = new List<string>();

        private class ProgressData
        {
            internal int fileCount;
            internal int lineCount;
            internal ConcurrentDictionary<string, object> hashSetLines = new ConcurrentDictionary<string, object>(StringComparer.OrdinalIgnoreCase);
        };

        // 用于线程安全的集合（多线程并发操作时必须使用）
        private ConcurrentDictionary<string, ProgressData> _typeProgress = new ConcurrentDictionary<string, ProgressData>();
        //ConcurrentBag<string> concurrentHashSetLines = new ConcurrentBag<string>();// 线程安全的集合

        private CancellationTokenSource _cts;

        public MainForm()
        {
            InitializeComponent();

            this.comboBox_RootPath.Items.Add("最近浏览的文件夹");
            //this.comboBox_RootPath.Items[0].e;
            if (File.Exists(_recentFolderPath))
            {
                var paths = File.ReadAllLines(_recentFolderPath);
                foreach (var path in paths)
                {
                    this.comboBox_RootPath.Items.Add(path);
                }

                if (paths.Length > 0)
                {
                    this.comboBox_RootPath.Items.Add("清除记录");
                }
            }

            this.listView1.View = View.Details;   // 详情视图（最常用）
            this.listView1.FullRowSelect = true;  // 选中整行
            this.listView1.GridLines = true;      // 显示网格线
            this.listView1.Columns.Add("类型", 150);
            this.listView1.Columns.Add("文件数", 150);
            this.listView1.Columns.Add("总行数", 150);
            this.listView1.Columns.Add("去重后", 150);

            // 初始化定时器
            _formTimer = new System.Windows.Forms.Timer();
            _formTimer.Tick += FormTimer_Tick; // 绑定事件
        }

        /// <summary>
        /// 点击浏览按钮
        /// </summary>
        private void Button_BrowseFolder_Click(object sender, EventArgs e)
        {
            string currentPath = this.comboBox_RootPath.Text;

            // 创建文件夹浏览对话框实例
            using (FolderBrowserDialog folderDialog = new FolderBrowserDialog())
            {
                // 设置对话框标题
                folderDialog.Description = @"请选择文件夹";
                folderDialog.ShowNewFolderButton = false;

                // 初始路径优先使用文本框中已有的值（可能是粘贴的）
                if (!string.IsNullOrEmpty(currentPath) && Directory.Exists(currentPath))
                {
                    folderDialog.SelectedPath = currentPath;
                }
                else
                {
                    folderDialog.SelectedPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
                }

                // 显示对话框，如果用户点击了确定按钮
                if (folderDialog.ShowDialog() == DialogResult.OK)
                {
                    // 将选中的文件夹路径显示在文本框中
                    this.comboBox_RootPath.Text = folderDialog.SelectedPath;
                }
            }
        }

        private async void comboBox_RootPath_TextChanged(object sender, EventArgs e)
        {
            string currentPath = this.comboBox_RootPath.Text;

            _type2Files.Clear();
            this.listBox_ExtName.Items.Clear();//
            this.listView1.Items.Clear();
            if (!Directory.Exists(currentPath))
                return;

            // 将文件夹加入到记录
            await Task.Run(() =>
            {
                if (!File.Exists(_recentFolderPath) || !File.ReadAllLines(_recentFolderPath).Contains(currentPath))
                {
                    File.AppendAllText(_recentFolderPath, currentPath + Environment.NewLine, Encoding.UTF8);
                }
            });

            this.listBox_ExtName.Items.Add("正在遍历文件夹……");

            // 递归遍历文件夹
            await Task.Run(() => TraverseDirectory(currentPath));

            // 递归完毕，准备添加
            this.listBox_ExtName.Items.Clear();

            // 排序所有类型
            var types = _type2Files.Keys.OrderBy(t => t).ToHashSet();

            // 将_usuallyTypes中的类型排在前面并且勾选
            foreach (var usuallyType in _usuallyTypes)
            {
                if (types.Contains(usuallyType))
                {
                    this.listBox_ExtName.Items.Add(usuallyType);
                    this.listBox_ExtName.SetItemChecked(this.listBox_ExtName.Items.Count - 1, true);
                    types.Remove(usuallyType);
                }
            }

            // 如果有"(无扩展名)"将排在最后(先将其移除)
            bool hasNullExt = types.Contains(@"(无扩展名)");
            if (hasNullExt)
            {
                types.Remove(@"(无扩展名)");
            }
            // 将剩余的types加入listBox
            foreach (var type in types)
            {
                this.listBox_ExtName.Items.Add(type);
            }
            // 补充"(无扩展名)"
            if (hasNullExt)
            {
                this.listBox_ExtName.Items.Add(@"(无扩展名)");
            }
        }

        private void comboBox_RootPath_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.comboBox_RootPath.Text == @"清除记录")
            {
                this.comboBox_RootPath.Items.Clear();
                this.comboBox_RootPath.Items.Add("最近浏览的文件夹");

                if (File.Exists(_recentFolderPath))
                {
                    File.Delete(_recentFolderPath);
                }

                _formTimer.Interval = 100; // 间隔100毫秒
                _formTimer.Tag = "Clear_comboBox_RootPath";
                _formTimer.Start();
            }
            else if (this.comboBox_RootPath.Text == @"最近浏览的文件夹")
            {
                _formTimer.Interval = 100; // 间隔100毫秒
                _formTimer.Tag = "Clear_comboBox_RootPath";
                _formTimer.Start();
            }
        }

        // 定时器触发事件（在UI线程执行，可直接操作控件）
        private void FormTimer_Tick(object sender, EventArgs e)
        {
            if (_formTimer.Tag is string strTag)
            {
                if (strTag == "Clear_comboBox_RootPath")
                {
                    this.comboBox_RootPath.Text = "";
                    _formTimer.Stop();
                }
                else if (strTag == "update_progress")
                {
                    UpdateProgress();
                }
            }
        }

        /// <summary>
        /// 递归遍历文件夹及其子文件夹
        /// </summary>
        private void TraverseDirectory(string path)
        {
            try
            {
                // 获取当前文件夹中的所有文件
                string[] files = Directory.GetFiles(path);
                foreach (string file in files)
                {
                    // 获取文件扩展名（包含.）
                    string extension = Path.GetExtension(file);
                    if (string.IsNullOrEmpty(extension))
                    {
                        extension = @"(无扩展名)";
                    }

                    if (!_type2Files.TryGetValue(extension, out var filePaths))
                    {
                        filePaths = new List<string>();
                        _type2Files.Add(extension, filePaths);
                    }
                    filePaths.Add(file);
                }

                // 递归处理子文件夹
                string[] subDirectories = Directory.GetDirectories(path);
                foreach (string subDir in subDirectories)
                {
                    TraverseDirectory(subDir);
                }
            }
            catch (UnauthorizedAccessException ex)
            {
                Console.WriteLine($@"没有访问权限: {path} - {ex.Message}");
            }
            catch (PathTooLongException ex)
            {
                Console.WriteLine($@"路径太长: {path} - {ex.Message}");
            }
            catch (IOException ex)
            {
                Console.WriteLine($@"I/O错误: {path} - {ex.Message}");
            }
        }

        /// <summary>
        /// 点击执行按钮
        /// </summary>
        private async void button_Do_Click(object sender, EventArgs e)
        {
            var startTime = DateTime.Now;

            // 清除原有结果
            this.listView1.Items.Clear();

            // 检查选中的文件类型
            _selectedItems.Clear();
            for (int i = 0; i < this.listBox_ExtName.Items.Count; i++)
            {
                if (this.listBox_ExtName.GetItemChecked(i) &&
                    this.listBox_ExtName.Items[i] is string item)
                {
                    _selectedItems.Add(item);
                }
            }
            if (_selectedItems.Count == 0)
            {
                MessageBox.Show(@"没有需要分析的文件");
                return;
            }

            {
                var tempItem = new ListViewItem("正在统计……");
                listView1.Items.Add(tempItem);
            }

            _formTimer.Interval = 200; // 间隔毫秒
            _formTimer.Tag = "update_progress";
            _formTimer.Start();

            this.button_Do.Enabled = false;
            _cts = new CancellationTokenSource();
            await Task.Run(() =>
            {
                _typeProgress.Clear();

                // 使用Parallel.ForEach实现并行处理
                var files = _selectedItems.SelectMany(item => _type2Files[item]).ToList();
                Parallel.ForEach(files, fileName =>
                {
                    string extension = Path.GetExtension(fileName);
                    if (string.IsNullOrEmpty(extension))
                    {
                        extension = @"(无扩展名)";
                    }

                    if (!_typeProgress.TryGetValue(extension, out var progress))
                    {
                        progress = new ProgressData();
                        _typeProgress.TryAdd(extension, progress);
                    }

                    progress.fileCount++;
                    var lines = File.ReadAllLines(fileName);
                    Interlocked.Add(ref progress.lineCount, lines.Length);// 累加总行数（线程安全）
                    foreach (var line in lines)
                    {
                        progress.hashSetLines.TryAdd(line, null);
                    }
                });
            });

            _formTimer.Stop();// 停止界面进度更新

            int filesTotal = 0;
            int linesTotal = 0;
            int hashSetLinesTotal = 0;
            this.listView1.Items.Clear();
            foreach (var item in _selectedItems)
            {
                var typeResult = _typeProgress[item];

                filesTotal += typeResult.fileCount;
                linesTotal += typeResult.lineCount;
                hashSetLinesTotal += typeResult.hashSetLines.Count;

                var row = new ListViewItem(item);
                row.SubItems.Add(typeResult.fileCount.ToString());// 文件数
                row.SubItems.Add(typeResult.lineCount.ToString());// 总行数
                row.SubItems.Add(typeResult.hashSetLines.Count.ToString());// 去重行数
                listView1.Items.Add(row);
            }

            {
                var totalItem = new ListViewItem("总计");
                totalItem.SubItems.Add(filesTotal.ToString());// 文件数
                totalItem.SubItems.Add(linesTotal.ToString());// 总行数
                totalItem.SubItems.Add(hashSetLinesTotal.ToString());// 去重行数
                listView1.Items.Add(totalItem);
            }

            {
                var ms = (DateTime.Now - startTime).TotalMilliseconds;
                var timeItem = new ListViewItem($"耗时：{(int)ms}毫秒");
                listView1.Items.Add(timeItem);
            }

            _cts.Dispose();
            this.button_Do.Enabled = true;
        }

        private void UpdateProgress()
        {
            if (this.listView1.Items.Count == 0 ||
                (this.listView1.Items[0].SubItems.Count > 0 && this.listView1.Items[0].SubItems[0].Text == @"正在统计……"))
            {
                this.listView1.Items.Clear();
                foreach (var item in _selectedItems)
                {
                    var row = new ListViewItem(item);
                    row.SubItems.Add("0/" + _type2Files[item].Count);// 文件数
                    row.SubItems.Add("0");// 总行数
                    row.SubItems.Add("0");// 去重行数
                    listView1.Items.Add(row);
                }
            }

            for (int i = 0; i < this.listView1.Items.Count; i++)
            {
                var row = this.listView1.Items[i] as ListViewItem;
                if (row.SubItems.Count == 4)
                {
                    var typeName = row.SubItems[0].Text;
                    if (_typeProgress.TryGetValue(typeName, out var currCount))
                    {
                        row.SubItems[1].Text = $@"{currCount.fileCount}/{_type2Files[typeName].Count}";
                        row.SubItems[2].Text = $@"{currCount.lineCount}";
                        row.SubItems[3].Text = $@"{currCount.hashSetLines.Count}";
                    }
                }
            }
        }
    }
}
